using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
using System.Linq;

namespace Engine.Input 
{
    public static class EnumUtil
    {
        public static IEnumerable<T> GetValues<T>()
        {
            return Enum.GetValues(typeof(T)).Cast<T>();
        }
    }

    public class InputReader
    {
        private Control listener;

        private Dictionary<KeyCodes, bool> listener_KeyCodes;
        private Dictionary<MouseButtons, bool> listener_MouseButtons;

        private bool isMouseFocused;
        public bool IsMouseFocused
        {
            get { return isMouseFocused; }
            set { isMouseFocused = value; }
        }

        private int absoluteMouseX;
        public int AbsoluteMouseX
        {
            get
            {
                return absoluteMouseX;
            }
        }

        private int absoluteMouseY;
        public int AbsoluteMouseY
        {
            get
            {

                return absoluteMouseY;
            }
        }

        private int absoluteMouseZ;
        public int AbsoluteMouseZ
        {
            get
            {
                return absoluteMouseZ;
            }
        }

        private int relativeMouseX;
        public int RelativeMouseX
        {
            get
            {
                return relativeMouseX;
            }
        }

        private int relativeMouseY;
        public int RelativeMouseY
        {
            get
            {
                return relativeMouseY;
            }
        }

        private int relativeMouseZ;
        public int RelativeMouseZ
        {
            get
            {
                return relativeMouseZ;
            }
        }


        private long mouseWheelTimeCaptured;
        private long mouseWheelTime;
        private long mouseMoveTimeCaptured;
        private long mouseMoveTime;

        public InputReader(Control target)
        {
            listener_KeyCodes = new Dictionary<KeyCodes, bool>();
            foreach (KeyCodes key in EnumUtil.GetValues<KeyCodes>())
            {
                if (!listener_KeyCodes.ContainsKey(key))
                {
                    listener_KeyCodes.Add(key, false);
                }
            }

            listener_MouseButtons = new Dictionary<MouseButtons, bool>();
            foreach (MouseButtons button in EnumUtil.GetValues<MouseButtons>())
            {
                if (!listener_MouseButtons.ContainsKey(button))
                {
                    listener_MouseButtons.Add(button, false);
                }
            }

            listener = target;
            listener.KeyDown += new KeyEventHandler(listener_KeyDown);
            listener.KeyUp += new KeyEventHandler(listener_KeyUp);
            listener.MouseDown += new MouseEventHandler(listener_MouseDown);
            listener.MouseUp += new MouseEventHandler(listener_MouseUp);
            listener.MouseWheel += new MouseEventHandler(listener_MouseWheel);
            listener.MouseMove += new MouseEventHandler(listener_MouseMove);
            listener.MouseEnter += new EventHandler(listener_MouseEnter);
            listener.MouseLeave += new EventHandler(listener_MouseLeave);
        }

        void listener_MouseLeave(object sender, EventArgs e)
        {
            IsMouseFocused = false;
            if (OnMouseLeave != null)
            {
                OnMouseLeave();
            }
        }

        void listener_MouseEnter(object sender, EventArgs e)
        {
            IsMouseFocused = true;
            if (OnMouseEnter != null)
            {
                OnMouseEnter();
            }
        }

        private void listener_KeyDown(object sender, KeyEventArgs e)
        {
            listener_KeyCodes[(KeyCodes)e.KeyCode] = true;

            listener_KeyCodes[KeyCodes.Alt] = e.Alt;
            listener_KeyCodes[KeyCodes.Control] = e.Control;
            listener_KeyCodes[KeyCodes.Shift] = e.Shift;
        }

        private void listener_KeyUp(object sender, KeyEventArgs e)
        {
            listener_KeyCodes[(KeyCodes)e.KeyCode] = false;

            listener_KeyCodes[KeyCodes.Alt] = e.Alt;
            listener_KeyCodes[KeyCodes.Control] = e.Control;
            listener_KeyCodes[KeyCodes.Shift] = e.Shift;
        }

        private void listener_MouseDown(object sender, MouseEventArgs e)
        {
            listener_MouseButtons[(MouseButtons)e.Button] = true;
            listener.Focus();
        }

        private void listener_MouseUp(object sender, MouseEventArgs e)
        {
            listener_MouseButtons[(MouseButtons)e.Button] = false;
        }

        private void listener_MouseMove(object sender, MouseEventArgs e)
        {
            int x = e.Location.X;
            relativeMouseX = x - absoluteMouseX;
            absoluteMouseX = x;

            int y = e.Location.Y;
            relativeMouseY = y - absoluteMouseY;
            absoluteMouseY = y;

            mouseMoveTime = DateTime.Now.Ticks;
        }

        private void listener_MouseWheel(object sender, MouseEventArgs e)
        {
            int delta = e.Delta;
            relativeMouseZ = delta;
            absoluteMouseZ += delta;

            mouseWheelTime = DateTime.Now.Ticks;


        }

        public void Capture()
        {
            if (mouseMoveTime == mouseMoveTimeCaptured)
            {
                relativeMouseX = 0;
                relativeMouseY = 0;
            }
            mouseMoveTimeCaptured = mouseMoveTime;

            if (mouseWheelTime == mouseWheelTimeCaptured)
            {
                relativeMouseZ = 0;
            }
            mouseWheelTimeCaptured = mouseWheelTime;
        }

        public bool IsKeyPressed(KeyCodes key)
        {
            bool result = listener_KeyCodes[key];
            return result;
        }

        public bool IsMousePressed(MouseButtons button)
        {
            bool result = listener_MouseButtons[button];
            return result;
        }

        public OnMouseEnterEvent OnMouseEnter;
        public OnMouseLeaveEvent OnMouseLeave;
        public delegate void OnMouseEnterEvent();
        public delegate void OnMouseLeaveEvent();
    }

}//end namespace Input